{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IDdZSPcLtKx4"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Hub Authors.\n",
        "\n",
        "Licensed under the Apache License, Version 2.0 (the \"License\");"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-g5By3P4tavy"
      },
      "outputs": [],
      "source": [
        "# Copyright 2019 The TensorFlow Hub Authors. All Rights Reserved.\n",
        "#\n",
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "#     http://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS, \n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License.\n",
        "# =============================================================================="
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vpaLrN0mteAS"
      },
      "source": [
        "# TF-Hub를 사용한 Bangla 문서 분류"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MfBg1C5NB3X0"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/hub/tutorials/bangla_article_classifier\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/hub/tutorials/bangla_article_classifier.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행하기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/hub/tutorials/bangla_article_classifier.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub에서 소스 보기</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/hub/tutorials/bangla_article_classifier.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드하기</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GhN2WtIrBQ4y"
      },
      "source": [
        "주의: pip로 python 패키지를 설치하는 외에도 이 노트북에서는 `sudo apt install`을 사용하여 시스템 패키지`unzip`을 설치합니다.\n",
        "\n",
        "이 colab은 비 영어/현지어로 텍스트를 분류하기 위해 [Tensorflow Hub](https://www.tensorflow.org/hub/)를 사용하는 데모입니다. 여기에서는 [Bangla](https://en.wikipedia.org/wiki/Bengali_language)를 현지어로 선택하고 사전 훈련된 단어 임베딩을 사용하여 Bangla 뉴스 기사를 5가지 범주로 분류하는 다중 클래스 분류 작업을 해결합니다. Bangla용 사전 훈련 임베딩은 157개 언어에 대해 사전 훈련된 단어 벡터를 게시한 Facebook 라이브러리인 [fastText](https://fasttext.cc/docs/en/crawl-vectors.html)에서 가져옵니다.\n",
        "\n",
        "먼저 TF-Hub의 사전 훈련된 임베딩 exporter를 사용하여 단어 임베딩을 텍스트 임베딩 모듈로 변환한 다음, Tensorflow의 사용자 친화적인 상위 수준 API인 [tf.keras](https://www.tensorflow.org/api_docs/python/tf/keras)로 분류자를 훈련하는 모듈을 사용하여 딥 러닝 모델을 빌드합니다. 여기에서 fastText 임베딩을 사용하더라도 다른 작업에서 사전 훈련된 다른 임베딩을 내보내고 Tensorflow Hub를 사용하여 신속하게 결과를 얻을 수 있습니다. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Q4DN769E2O_R"
      },
      "source": [
        "## 설정"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9Vt-StAAZguA"
      },
      "outputs": [],
      "source": [
        "%%bash\n",
        "# https://github.com/pypa/setuptools/issues/1694#issuecomment-466010982\n",
        "pip install gdown --no-use-pep517"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "WcBA19FlDPZO"
      },
      "outputs": [],
      "source": [
        "%%bash\n",
        "sudo apt-get install -y unzip"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zSeyZMq-BYsu"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "\n",
        "import tensorflow as tf\n",
        "import tensorflow_hub as hub\n",
        "\n",
        "import gdown\n",
        "import numpy as np\n",
        "from sklearn.metrics import classification_report\n",
        "import matplotlib.pyplot as plt\n",
        "import seaborn as sns"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9FB7gLU4F54l"
      },
      "source": [
        "# 데이터세트\n",
        "\n",
        "다양한 Bangla 뉴스 포털에서 수집한 약 3,76,226개의 기사가 있고 경제, 국내, 국제, 스포츠 및 엔터테인먼트의 5가지 범주로 분류된 [BARD](https://www.researchgate.net/publication/328214545_BARD_Bangla_Article_Classification_Using_a_New_Comprehensive_Dataset)(Bangla Article Dataset)를 사용합니다. 이 ([bit.ly/BARD_DATASET](bit.ly/BARD_DATASET)) 링크가 가리키는 Google 드라이브 파일을 [이](https://github.com/tanvirfahim15/BARD-Bangla-Article-Classifier) GitHub 리포지토리에서 다운로드합니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zdQrL_rwa-1K"
      },
      "outputs": [],
      "source": [
        "gdown.download(\n",
        "    url='https://drive.google.com/uc?id=1Ag0jd21oRwJhVFIBohmX_ogeojVtapLy',\n",
        "    output='bard.zip',\n",
        "    quiet=True\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "P2YW4GGa9Y5o"
      },
      "outputs": [],
      "source": [
        "%%bash\n",
        "unzip -qo bard.zip"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "js75OARBF_B8"
      },
      "source": [
        "# 사전 훈련된 단어 벡터를 TF-Hub 모듈로 내보내기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-uAicYA6vLsf"
      },
      "source": [
        "TF-Hub는 [여기에서](https://github.com/tensorflow/hub/tree/master/examples/text_embeddings_v2) 단어 임베딩을 TF-Hub 텍스트 임베딩 모듈로 변환하기 위한 몇 가지 편리한 스크립트를 제공합니다. Bangla 또는 다른 언어 모듈을 만들려면 .txt 또는 .vec 파일을 포함하는 단어를 export_v2.py와 동일한 디렉토리로 다운로드하고 스크립트를 실행하기만 하면 됩니다.\n",
        "\n",
        "Exporter는 임베딩 벡터를 읽고 Tensorflow [SavedModel](https://www.tensorflow.org/beta/guide/saved_model)로 내보냅니다. SavedModel에는 가중치와 그래프를 포함한 완전한 TensorFlow 프로그램이 포함되어 있습니다. TF-Hub는 SavedModel을 텍스트 분류를 위한 모델을 빌드하는 데 사용할 [모듈](https://www.tensorflow.org/hub/api_docs/python/hub/Module)로 로드할 수 있습니다. 모델을 빌드하기 위해 tf.keras를 사용하므로 Hub 모듈이 Keras 레이어로 사용할 래퍼를 제공하는 [hub.KerasLayer](https://www.tensorflow.org/hub/api_docs/python/hub/KerasLayer)를 사용할 것입니다.\n",
        "\n",
        "먼저 fastText에서 단어 임베딩을 가져오고 TF-Hub [리포지토리](https://github.com/tensorflow/hub)에서 임베딩 exporter를 가져옵니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5DY5Ze6pO1G5"
      },
      "outputs": [],
      "source": [
        "%%bash\n",
        "curl -O https://dl.fbaipublicfiles.com/fasttext/vectors-crawl/cc.bn.300.vec.gz\n",
        "curl -O https://raw.githubusercontent.com/tensorflow/hub/master/examples/text_embeddings_v2/export_v2.py\n",
        "gunzip -qf cc.bn.300.vec.gz --k"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PAzdNZaHmdl1"
      },
      "source": [
        "그런 다음 임베딩 파일에서 exporter 스크립트를 실행합니다. fastText 임베딩에는 헤더 행이 있고 크기가 매우 크기 때문에(모듈로 변환한 후 bangla의 경우 약 3.3GB) 첫 번째 행을 무시하고 처음 100,000개의 토큰만 텍스트 임베딩 모듈로 내보냅니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Tkv5acr_Q9UU"
      },
      "outputs": [],
      "source": [
        "%%bash\n",
        "python export_v2.py --embedding_file=cc.bn.300.vec --export_path=text_module --num_lines_to_ignore=1 --num_lines_to_use=100000"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "k9WEpmedF_3_"
      },
      "outputs": [],
      "source": [
        "module_path = \"text_module\"\n",
        "embedding_layer = hub.KerasLayer(module_path, trainable=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fQHbmS_D4YIo"
      },
      "source": [
        "텍스트 임베딩 모듈은 문자열의 1D 텐서에 있는 문장 배치를 입력으로 받아 문장에 해당하는 형상의 임베딩 벡터(batch_size, embedding_dim)를 출력합니다. 공백으로 분할하여 입력을 전처리합니다. 단어 임베딩은 `sqrtn` sqrtn combiner를 사용하여 문장 임베딩에 결합됩니다([여기](https://www.tensorflow.org/api_docs/python/tf/nn/embedding_lookup_sparse) 참조). 데모를 위해 Bangla 단어 목록을 입력으로 전달하고 해당 임베딩 벡터를 얻습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Z1MBnaBUihWn"
      },
      "outputs": [],
      "source": [
        "embedding_layer(['বাস', 'বসবাস', 'ট্রেন', 'যাত্রী', 'ট্রাক']) "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4KY8LiFOHmcd"
      },
      "source": [
        "# Tensorflow 데이터세트로 변환하기\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pNguCDNe6bvz"
      },
      "source": [
        "데이터세트가 정말 크기 때문에 메모리에 전체 데이터세트를 로드하는 대신 [Tensorflow 데이터세트](https://www.tensorflow.org/api_docs/python/tf/data/Dataset) 기능을 사용하여 일괄적으로 런타임에 샘플을 생성하는 데 생성기를 사용합니다. 데이터세트는 또한 매우 불균형적이므로 생성기를 사용하기 전에 데이터세트를 셔플합니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "bYv6LqlEChO1"
      },
      "outputs": [],
      "source": [
        "dir_names = ['economy', 'sports', 'entertainment', 'state', 'international']\n",
        "\n",
        "file_paths = []\n",
        "labels = []\n",
        "for i, dir in enumerate(dir_names):\n",
        "  file_names = [\"/\".join([dir, name]) for name in os.listdir(dir)]\n",
        "  file_paths += file_names\n",
        "  labels += [i] * len(os.listdir(dir))\n",
        "  \n",
        "np.random.seed(42)\n",
        "permutation = np.random.permutation(len(file_paths))\n",
        "\n",
        "file_paths = np.array(file_paths)[permutation]\n",
        "labels = np.array(labels)[permutation]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8b-UtAP5TL-W"
      },
      "source": [
        "셔플한 후 훈련 및 검증 예제에서 레이블 분포를 확인할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "mimhWVSzzAmS"
      },
      "outputs": [],
      "source": [
        "train_frac = 0.8\n",
        "train_size = int(len(file_paths) * train_frac)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4BNXFrkotAYu"
      },
      "outputs": [],
      "source": [
        "# plot training vs validation distribution\n",
        "plt.subplot(1, 2, 1)\n",
        "plt.hist(labels[0:train_size])\n",
        "plt.title(\"Train labels\")\n",
        "plt.subplot(1, 2, 2)\n",
        "plt.hist(labels[train_size:])\n",
        "plt.title(\"Validation labels\")\n",
        "plt.tight_layout()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RVbHb2I3TUNA"
      },
      "source": [
        "생성기를 사용하여 [데이터세트](https://www.tensorflow.org/api_docs/python/tf/data/Dataset)를 생성하려면 먼저 file_paths에서 각 기사를 읽고 레이블 배열에서 레이블을 읽어 각 스텝에서 하나의 훈련 예제를 생성하는 생성기 함수를 작성합니다. 이 생성기 함수를 [tf.data.Dataset.from_generator](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#from_generator) 메서드에 전달하고 출력 유형을 지정합니다. 각 훈련 예제는 tf.string 데이터 형식의 기사와 원-핫 인코딩된 레이블을 포함하는 튜플입니다. [`skip`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#skip) 및 [`take`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#take) 메서드를 사용하여 80-20의 훈련-검증 분할로 데이터세트를 분할합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "eZRGTzEhUi7Q"
      },
      "outputs": [],
      "source": [
        "def load_file(path, label):\n",
        "    return tf.io.read_file(path), label"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2g4nRflB7fbF"
      },
      "outputs": [],
      "source": [
        "def make_datasets(train_size):\n",
        "  batch_size = 256\n",
        "\n",
        "  train_files = file_paths[:train_size]\n",
        "  train_labels = labels[:train_size]\n",
        "  train_ds = tf.data.Dataset.from_tensor_slices((train_files, train_labels))\n",
        "  train_ds = train_ds.map(load_file).shuffle(5000)\n",
        "  train_ds = train_ds.batch(batch_size).prefetch(tf.data.experimental.AUTOTUNE)\n",
        "\n",
        "  test_files = file_paths[train_size:]\n",
        "  test_labels = labels[train_size:]\n",
        "  test_ds = tf.data.Dataset.from_tensor_slices((test_files, test_labels))\n",
        "  test_ds = test_ds.map(load_file)\n",
        "  test_ds = test_ds.batch(batch_size).prefetch(tf.data.experimental.AUTOTUNE)\n",
        "\n",
        "\n",
        "  return train_ds, test_ds"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8PuuN6el8tv9"
      },
      "outputs": [],
      "source": [
        "train_data, validation_data = make_datasets(train_size)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MrdZI6FqPJNP"
      },
      "source": [
        "# 모델 훈련 및 평가"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jgr7YScGVS58"
      },
      "source": [
        "keras에서 다른 레이어로 사용하기 위해 모듈 주위에 래퍼를 이미 추가했으므로 레이어의 선형 스택인 작은 [순차](https://www.tensorflow.org/api_docs/python/tf/keras/Sequential) 모델을 만들 수 있습니다. 다른 레이어와 마찬가지로 `model.add`로 텍스트 임베딩 모듈을 추가할 수 있습니다. 손실과 옵티마이저를 지정하여 모델을 컴파일하고 10개 epoch 동안 훈련합니다. `tf.keras` API는 tensorflow 데이터세트를 입력으로 처리할 수 있으므로 모델 훈련을 위해 데이터세트 인스턴스를 fit 메서드로 전달할 수 있습니다. 생성기 함수를 사용하기 때문에 tf.data가 샘플을 생성하고 배치 처리하여 모델에 공급하는 작업을 처리합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WhCqbDK2uUV5"
      },
      "source": [
        "## 모델"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nHUw807XPPM9"
      },
      "outputs": [],
      "source": [
        "def create_model():\n",
        "  model = tf.keras.Sequential([\n",
        "    tf.keras.layers.Input(shape=[], dtype=tf.string),\n",
        "    embedding_layer,\n",
        "    tf.keras.layers.Dense(64, activation=\"relu\"),\n",
        "    tf.keras.layers.Dense(16, activation=\"relu\"),\n",
        "    tf.keras.layers.Dense(5),\n",
        "  ])\n",
        "  model.compile(loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
        "      optimizer=\"adam\", metrics=['accuracy'])\n",
        "  return model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5J4EXJUmPVNG"
      },
      "outputs": [],
      "source": [
        "model = create_model()\n",
        "# Create earlystopping callback\n",
        "early_stopping_callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=3)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZZ7XJLg2u2No"
      },
      "source": [
        "## 훈련"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OoBkN2tAaXWD"
      },
      "outputs": [],
      "source": [
        "history = model.fit(train_data, \n",
        "                    validation_data=validation_data, \n",
        "                    epochs=5, \n",
        "                    callbacks=[early_stopping_callback])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XoDk8otmMoT7"
      },
      "source": [
        "## 평가"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "G5ZRKGOsXEh4"
      },
      "source": [
        "각 epoch에 대한 손실 및 정확성 값을 포함하는 `fit` 메서드에서 반환된 `history` 객체를 사용하여 훈련 및 검증 데이터에 대한 정확성과 손실 곡선을 시각화할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "V6tOnByIOeGn"
      },
      "outputs": [],
      "source": [
        "# Plot training & validation accuracy values\n",
        "plt.plot(history.history['accuracy'])\n",
        "plt.plot(history.history['val_accuracy'])\n",
        "plt.title('Model accuracy')\n",
        "plt.ylabel('Accuracy')\n",
        "plt.xlabel('Epoch')\n",
        "plt.legend(['Train', 'Test'], loc='upper left')\n",
        "plt.show()\n",
        "\n",
        "# Plot training & validation loss values\n",
        "plt.plot(history.history['loss'])\n",
        "plt.plot(history.history['val_loss'])\n",
        "plt.title('Model loss')\n",
        "plt.ylabel('Loss')\n",
        "plt.xlabel('Epoch')\n",
        "plt.legend(['Train', 'Test'], loc='upper left')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "D54IXLqcG8Cq"
      },
      "source": [
        "## 예측\n",
        "\n",
        "검증 데이터에 대한 예측값을 얻고 혼동 행렬을 확인하여 5개 클래스 각각에 대한 모델의 성능을 확인할 수 있습니다. `predict` 메서드는 `np.argmax`를 사용하여 클래스 레이블로 변환하는 각 클래스의 확률에 대한 n-d 배열을 반환합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dptEywzZJk4l"
      },
      "outputs": [],
      "source": [
        "y_pred = model.predict(validation_data)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7Dzeml6Pk0ub"
      },
      "outputs": [],
      "source": [
        "y_pred = np.argmax(y_pred, axis=1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "T4M3Lzg8jHcB"
      },
      "outputs": [],
      "source": [
        "samples = file_paths[0:3]\n",
        "for i, sample in enumerate(samples):\n",
        "  f = open(sample)\n",
        "  text = f.read()\n",
        "  print(text[0:100])\n",
        "  print(\"True Class: \", sample.split(\"/\")[0])\n",
        "  print(\"Predicted Class: \", dir_names[y_pred[i]])\n",
        "  f.close()\n",
        "  "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PlDTIpMBu6h-"
      },
      "source": [
        "## 성능 비교\n",
        "\n",
        "이제 `labels`에서 검증 데이터의 올바른 레이블을 가져와 예측값과 비교하고 [classification_report](http://scikit-learn.org/stable/modules/generated/sklearn.metrics.classification_report.html)를 생성합니다. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "mqrERUCS1Xn7"
      },
      "outputs": [],
      "source": [
        "y_true = np.array(labels[train_size:])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NX5w-NuTKuVP"
      },
      "outputs": [],
      "source": [
        "print(classification_report(y_true, y_pred, target_names=dir_names))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "p5e9m3bV6oXK"
      },
      "source": [
        "또한 모델의 성능을 0.96 정밀도를 보고하는 원본 [논문](https://www.researchgate.net/publication/328214545_BARD_Bangla_Article_Classification_Using_a_New_Comprehensive_Dataset)에서 얻은 결과와 비교할 수 있습니다. 원래 저자는 구두점 및 숫자를 삭제하고 가장 빈번한 25개의 제외어를 제거하는 등 데이터세트에 수행된 많은 전처리 스텝을 설명했습니다. classification_report에서 볼 수 있듯이 전처리 없이 5개 epoch 동안만 훈련한 후에도 0.96의 정밀도와 정확성이 얻어집니다!\n",
        "\n",
        "이 예제에서는 임베딩 모듈에서 Keras 레이어를 만들 때 `trainable=False`를 설정했습니다. 이것은 임베딩 가중치가 훈련 중에 업데이트되지 않음을 의미합니다. 이 데이터세트에서 단 두 번의 epoch로 97% 정확성에 도달하려면 True로 설정해 보세요. "
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "IDdZSPcLtKx4"
      ],
      "name": "bangla_article_classifier.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
